#include "xtask_mgr.h"

#include "xworker_queue.h"
#include "xworker_double_queue.h"
#include "xworker_priority_queue.h"
#include "xworker_single_queue.h"
#include "xworker.h"

#include "xdata_structure.h"
#include <string>


namespace xge{

  using xge_internal::Worker;
  using xge_internal::WorkerSingleQueue;
  using xge_internal::WorkerDoubleQueue;
  using xge_internal::WorkerPriorityQueue;

  // Task helper is the helper class for the task manager , it contains 
  // the function of dealing with the task load balancing stuff ,and also
  // it contains the function of hidden the task queue internally 
  class TaskManager::TaskHelper {
  public:
    int  PushTask(  const TaskPtr& task_ptr , bool delay /* = true */ );
    void SyncQueueTask( int type ) ;
    int  CreateWorkerQueue ( int type );
    int  DestroyManualQueue( bool post_quit_soon /* = POST_QUIT_SOON  */, bool blocking /* = true */ );
    const TripleResult Wait();
    const TripleResult Wait( size_t ms );
    bool Initialize();
    // Call this function inside of at-exit callback function
    void Destroy   ();
  private:
    // Simply using String and std::string as the string container
    void MakeStringName( const int type , String* thread_name , std::string* debug_name );
  private:

    typedef Worker< WorkerSingleQueue > SingleWorker;
    typedef Worker< WorkerDoubleQueue > DoubleWorker;
    typedef Worker< WorkerPriorityQueue > PriorityWorker;

    // Now we should build a container to hold each worker queue 
    DoubleWorker* comm_queue_ ; // this queue is for common using stuff
    // Now we create manually created queue container 
    typedef list< SingleWorker* >::List SingleWorkerList;
    typedef list< DoubleWorker* >::List DoubleWorkerList;
    typedef list< PriorityWorker* >::List PriorityWorkerList;
    // Now we simply create a array to hold this pointer 
    void* container_array_[3];
  };

  // Queue type naming tips 
  // We just name the queue type thread as SingleWorkerQueueThread#unique_number#

#define string_as_array(str) (&(*((str).begin())))
  void TaskManager::TaskHelper::MakeStringName( const int type , String* thread_name , std::string* debug_name ) {
    // very verbose function implementation , I can choose to use the macro to do the implementation
    // however , I do not sure the macro contains the definition of macro .
    thread_name->clear();
    debug_name->clear();
    // now do the naming here 
    switch( type ) {
    case WorkerQueue::QUEUE_TYPE_SINGLE_QUEUE : 
      // single queue type 
      SingleWorkerList* single_queue = (SingleWorkerList*)(container_array_[type-1]);
      const size_t size = single_queue->size();
      // this size can at most be 9 , impossible to reach 10 
      // so the name must be SingleWorkerQueueThread#*# , whose length is 26(32)
      thread_name->resize(32);
      debug_name->resize(32);
      // now do the formating stuff 
      int ret=
#ifdef XGE_USE_WIDE_CHAR
      _vswprintf(string_as_array(thread_name),_xT("SingleWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#else
      vsprintf(string_as_array(thread_name),_xT("SingleWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#endif
      ret = vsprintf(string_as_array(thread_name),"SingleWorkerQueueThread#%d#",size);
      debug_name->resize(ret);
      return;
    case WorkerQueue::QUEUE_TYPE_DOUBLE_QUEUE:
      DoubleWorkerList* double_queue = (DoubleWorkerList*)(container_array_[type-1]);
      const size_t size = double_queue->size();
      // this size can at most be 9 ,
      // so the name must be DoubleWorkerQueueThread#*# whose length is 26(32)
      thread_name->resize(32);
      debug_name->resize(32);
#ifdef XGE_USE_WIDE_CHAR
      _vswprintf(string_as_array(thread_name),_xT("DoubleWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#else
      vsprintf(string_as_array(thread_name),_xT("DoubleWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#endif
      ret = vsprintf(string_as_array(thread_name),"DoubleWorkerQueueThread#%d#",size);
      debug_name->resize(ret);
      return;
    case WorkerQueue::QUEUE_TYPE_PRIROITY_QUEUE:
      PriorityWorkerList* double_queue = (PriorityWorkerList*)(container_array_[type-1]);
      const size_t size = double_queue->size();
      // this size can at most be 9 ,
      // so the name must be PriorityWorkerQueueThread#*# whose length is 28(32)
      thread_name->resize(32);
      debug_name->resize(32);
#ifdef XGE_USE_WIDE_CHAR
      _vswprintf(string_as_array(thread_name),_xT("PriorityWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#else
      vsprintf(string_as_array(thread_name),_xT("PriorityWorkerQueueThread#%d#"),size);
      thread_name->resize(ret);
#endif
      ret = vsprintf(string_as_array(thread_name),"PriorityWorkerQueueThread#%d#",size);
      debug_name->resize(ret);
      return;
    }
    default:
      //can not be here 
      return;
  }
#undef string_as_array

  bool TaskManager::TaskHelper::Initialize() {
    // Create the common worker queue for using
    comm_queue_ = new DoubleWorker();
    if( !comm_queue_->Dispatch( _xT("CommonUsedQueue") , "CommonUsedQueue") ) {
      return false;
    }
    // Create the container array 
    container_array_[0] = new SingleWorkerList();
    container_array_[1] = new DoubleWorkerList();
    container_array_[2] = new PriorityWorkerList();
    // Ok
    return true;
  }

  void TaskManager::TaskHelper::Destroy() {
    // destroy
    // 1. destroy the common used task queue
    if( !comm_queue_->Destroy(true,true) ) {
      SYS_LOG(WARNING,false,_xT("Can not destroy common queue,this seems to be impossible!"));
    }
    // 2. destroy the container queue array , if it really involves some
    DestroyManualQueue(true,true);
    return;
  }

  // Verbose and ugly , but it works 
  // Using the variable macro parameter 
  // to meet the parameter version of this wait function 
#define IMPLEMENT_WAIT(ListType,Index,...) \
  ListType* ListType##list_ptr = (ListType*)(container_array_[Index]); \
  ListType::iterator ListType##list_ib = ListType##list_ptr->begin() ; \
  ListType::iterator ListType##list_ie = ListType##list_ptr->end(); \
  while( ListType##list_ib != ListType##list_ie ) { \
  if( (*ListType##list_ib)->HasPostDestroyRequest() ) { \ 
  const TripleResult ListType##res( (*ListType##list_ib)->Wait( __VA_ARGS__ ) ); \
  if( ListType##res == TripleResult::kException ) { \
  ret = TripleResult::kException; \
  } else if( ListType##res == TripleResult::kFailed ) { \
  ret = TripleResult::kFailed; \
  } }
    ++ListType##list_ib; \
  }

  const TripleResult TaskManager::TaskHelper::Wait() {
    // Since the 3 type of list is same , so we just use
    // a macro to save some verbose language and improve
    // the maintainable aspects . 
    // The idea is simple , we just iterating the list
    // and find out those thread which has set the HasPostDestroyRequest
    // tag , so we wait this kind of thread and do the 
    // synchronization .
    TripleResult ret(TripleResult::kSucceded);


    // Implementing this stuff 
    IMPLEMENT_WAIT(SingleWorkerList,0)
    IMPLEMENT_WAIT(DoubleWorker,1)
    IMPLEMENT_WAIT(PriorityWorkerList,2)

    return ret;
  }
  // Implementation as above
  const TripleResult TaskManager::TaskHelper::Wait( size_t ms ) { 
    TripleResult ret(TripleResult::kSucceded);
    IMPLEMENT_WAIT(SingleWorkerList,0,ms)
    IMPLEMENT_WAIT(DoubleWorker,1,ms)
    IMPLEMENT_WAIT(PriorityWorkerList,2,ms)
    return ret;
  }

#undef IMPLEMENT_WAIT

#define IMPLEMENT_SYNC(TaskType,Index) \
  TaskType* TaskType##ptr = (TaskType*)(container_array_[Index]); \
  TaskType::iterator TaskType##ib = TaskType##ptr->begin(); \
  TaskType::iterator TaskType##ie = TaskType##ptr->end(); \
  while( TaskType##ib != TaskType##ie ) { \
  TaskType##ib->Sync(); \ 
  ++TaskType##ib; \
  }
  void TaskManager::TaskHelper::SyncQueueTask( int type ) {
    bool sync_boolean[3] = {false};
    if( type == -1 ) {
      sync_boolean[0] = sync_boolean[1] = sync_boolean[2] = true; 
    } else {
      sync_boolean[type-1] = true; 
    }
    if( sync_boolean[0] ) {
      IMPLEMENT_SYNC(SingleWorkerList,0)
    }
    if( sync_boolean[1] ) {
      IMPLEMENT_SYNC(DoubleWorkerList,1)
      comm_queue_->Sync();
    }
    if( sync_boolean[2] ) {
      IMPLEMENT_SYNC(DoubleWorkerList,1)
    }
  }

  int TaskManager::TaskHelper::PushTask( const TaskPtr& task_ptr , bool delay ) {
    int task_type = task_ptr->type();
  }





